﻿/*****************************************************************//**
 * \file   Num3.h
 * \brief  Num3
 * 
 * \author Wyatt
 * \date   January 2022
 *********************************************************************/
#ifndef _CODE_LIB_NUM3_H
#define _CODE_LIB_NUM3_H
#include <math.h>

template<typename Type> struct SNum3
{
	template <typename U> SNum3(const SNum3<U>& r) : x(r.x), y(r.y), z(r.z) {}
	SNum3<Type>(const Type& v0 = Type(0.), const Type& v1 = Type(0.), const Type& v2 = Type(0.))
	{
		v[0] = v0;
		v[1] = v1;
		v[2] = v2;
	}
	SNum3<Type>(const Type* val)
	{
		v[0] = val[0];
		v[1] = val[1];
		v[2] = val[2];
	}
	union {
		struct { Type x; Type y; Type z; };
		struct { Type alpha; Type beta; Type theta; };
		Type v[3];
	};
	template<typename> friend struct SNum3;
	SNum3<Type>& operator=(const SNum3<Type> &src)
	{		
		v[0] = src.v[0];
		v[1] = src.v[1];
		v[2] = src.v[2];
		return *this;
	}
	SNum3<Type>& operator+=(const SNum3<Type> &src)
	{		
		v[0] += src.v[0];
		v[1] += src.v[1];
		v[2] += src.v[2];
		return *this;
	}	
	SNum3<Type>& operator-=(const SNum3<Type> &src)
	{		
		v[0] -= src.v[0];
		v[1] -= src.v[1];
		v[2] -= src.v[2];
		return *this;
	}
	SNum3<Type>& operator*=(Type src)
	{		
		v[0] *= src;
		v[1] *= src;
		v[2] *= src;
		return *this;
	}
	SNum3<Type> operator+(const SNum3<Type> &src)
	{		
		SNum3<Type> tmp = *this;
		tmp+=src;
		return tmp;
	}
	SNum3<Type> operator-(const SNum3<Type> &src)
	{		
		SNum3<Type> tmp = *this;
		tmp-=src;
		return tmp;
	}
	SNum3<Type> operator*(Type src)
	{		
		SNum3<Type> tmp = *this;
		tmp*=src;
		return tmp;
	}
	operator const Type*() const 
	{
		return v;
	}
	Type &  operator[](int i) { return v[i]; }
	const Type & operator[](int i) const { return v[i]; }
	Type* operator* ()
	{
		return v;
	}
	SNum3<Type> & operator /=(const Type d)
	{
		*this *= (1.0f/d);
		return *this;
	}
	SNum3<Type> & operator *=(const SNum3<Type> & a_vec)
	{
		v[0] *= a_vec.v[0];
		v[1] *= a_vec.v[1];
		v[2] *= a_vec.v[2];
		return *this;
	}
	SNum3<Type> operator-() const
	{
		return SNum3<Type>(-v[0], -v[1], -v[2]);
	}
	friend SNum3<Type> operator *(const SNum3<Type> & a_vec, const Type d)
	{ 
		return SNum3<Type>(a_vec.v[0] * d, a_vec.v[1] * d, a_vec.v[2] * d);
	}
	friend SNum3<Type> operator *(const Type d, const SNum3<Type> & a_vec)
	{ 
		return a_vec * d; 
	}
	friend SNum3<Type> operator /(const SNum3<Type> & a_vec, const Type d)
	{ 
		return SNum3<Type>(a_vec.v[0] / d, a_vec.v[1] / d, a_vec.v[2] / d);
	}
	friend SNum3<Type> operator *(const SNum3<Type> & v1, const SNum3<Type> & v2)
	{	
		return SNum3<Type>(v1.v[0] * v2.v[0],v1.v[1] * v2.v[1],v1.v[2] * v2.v[2]);
	}
	friend SNum3<Type> operator +(const SNum3<Type> & v1, const SNum3<Type> & v2)
	{	
		return SNum3<Type>(v1.v[0] + v2.v[0],v1.v[1] + v2.v[1],v1.v[2] + v2.v[2]);
	}
	friend SNum3<Type> operator -(const SNum3<Type> & v1, const SNum3<Type> & v2)
	{	
		return SNum3<Type>(v1.v[0] - v2.v[0],v1.v[1] - v2.v[1],v1.v[2] - v2.v[2]);	
	}
	friend bool operator ==(const SNum3<Type> & v1, const SNum3<Type> & v2)
	{ 
		return (v1.v[0]==v2.v[0] && v1.v[1]==v2.v[1] && v1.v[2]==v2.v[2]); 
	}
	friend bool operator !=(const SNum3<Type> & v1, const SNum3<Type> & v2)
	{ 
		return !(v1 == v2); 
	}
	SNum3<Type> & set(const Type val[3])
	{
		v[0] = val[0];
		v[1] = val[1];
		v[2] = val[2];

		return *this;
	}
	SNum3<Type> & setVal(Type a_x, Type a_y, Type a_z)
	{
		v[0] = a_x;
		v[1] = a_y;
		v[2] = a_z;
		return *this;
	}
	SNum3<Type>& setValAll(Type a_)
	{
		v[0] = a_;
		v[1] = a_;
		v[2] = a_;
		return *this;
	}
	const Type * value() const
	{
		return &v[0];
	}
	Type dot(const SNum3<Type> & a_vec) const
	{
		return (v[0] * a_vec[0] + v[1] * a_vec[1] + v[2] * a_vec[2]);
	}
	Type len() const
	{
		return (Type)sqrt(sqrLength());
	}
	Type sqrLength() const
	{
		return (v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]);
	}
	Type normalize()
	{
		Type magnitude = len();
		if (magnitude != 0.0)
			(*this) *= (Type)(1.0 / magnitude);
		else
			setVal(0.0, 0.0, 0.0);
		return magnitude;
	}
	SNum3<Type> cross(const SNum3<Type> & a_vec) const
	{
		return SNum3<Type>(v[1] * a_vec[2] - a_vec[1] * v[2],
			v[2] * a_vec[0] - a_vec[2] * v[0],
			v[0] * a_vec[1] - a_vec[0] * v[1]);
	}
	bool isParallel(const SNum3& val)
	{
		Type dotProduct = this->Dot(val);
		Type vlen = val.len();
		Type len = this->len();
		if (fabs(fabs(dotProduct) - len * vlen) < 1e-6) {
			return true;
		}
		return false;
	}
	bool isZero() const
	{
		return (x == 0 && y == 0 && z == 0);
	}
	void negate()
	{
		setVal(-v[0], -v[1], -v[2]);
	}
	bool equals(const SNum3<Type> & vec, const Type tol = 1e-5) const
	{
		Type xdist = v[0] - vec.v[0];
		Type ydist = v[1] - vec.v[1];
		Type zdist = v[2] - vec.v[2];
		return ((xdist*xdist + ydist*ydist + zdist*zdist) <= tol);
	}
};

typedef SNum3<double> SNum3d;

//求坐标转换的数据格式
struct Point3D
{
	double _x, _y, _z;
	Point3D(double x = 0, double y = 0, double z = 0) :_x(x), _y(y), _z(z) {};
};

#endif // _CODE_LIB_NUM3_H